package com.bum.rss.site.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

public class BaseParser {
	public static final String[]	FIREFOX_HEADERS	= {
			"User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2",
			"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
			"Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
			"Accept-Encoding", "gzip",
			"Accept-Language", "en,vi;q=0.5"
													};

	public static final String[]	WAP_HEADERS		= {
			"User-Agent", "Nokia3650/1.0 UP.Browser/6.2",
			"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
			"Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
			"Accept-Language", "en-us,en;q=0.5"
													};

	public static final String[]	IPHONE_HEADERS	= {
			"User-Agent",
			"Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7",
			"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
			"Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
			"Accept-Language", "en-us,en;q=0.5"
													};

	public static final String[]	ANDROID_HEADERS	= {
			"User-Agent",
			"Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 GLOBAL Build/S273) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
			"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
			"Accept-Charset", "utf-8;q=0.7,*;q=0.7",
			"Accept-Language", "en-us,en;q=0.5",
			"Cookie", "znews_mobile=1"
													};

	public static byte[] loadImage(String hostName) {
		return loadImage(hostName, null);
	}

	public static void main(String[] args) throws Exception {
		String link = "htTp://mE.ola.vn/";
		URI uri = new URI(null, link, null);
		System.out.println(uri.normalize().toURL());
	}

	public static URLConnection getConnection(String hostName, String[] headers) throws Exception {
		URI uri = new URI(null, hostName, null);
		URL url = uri.normalize().toURL();
		URLConnection conn = url.openConnection();
		// conn.setRequestProperty("Host", hostName);

		if (headers != null) {
			for (int i = 0, n = headers.length / 2; i < n; i++) {
				conn.setRequestProperty(headers[2 * i], headers[2 * i + 1]);
			}
		} else {
			for (int i = 0, n = FIREFOX_HEADERS.length / 2; i < n; i++) {
				conn.setRequestProperty(FIREFOX_HEADERS[2 * i], FIREFOX_HEADERS[2 * i + 1]);
			}
		}
		return conn;
	}

	public static byte[] loadImage(String hostName, String[] headers) {
		try {
			URLConnection conn = getConnection(hostName, headers);

			InputStream inStream = conn.getInputStream();
			ByteArrayOutputStream arrayStream = new ByteArrayOutputStream();

			byte[] buffer = new byte[1024];
			int byteRead = 0;
			while ((byteRead = inStream.read(buffer)) > 0) {
				arrayStream.write(buffer, 0, byteRead);
			}
			inStream.close();

			return arrayStream.toByteArray();
		} catch (Exception e) {
		}

		return null;
	}

	public static String loadHtml(String hostName) {
		return loadHtml(hostName, null, null, null);
	}

	public static String loadHtml(String hostName, String charset) {
		return loadHtml(hostName, null, null, charset);
	}

	public static String loadHtml(String hostName, boolean followRedirects) {
		return loadHtml(hostName, null, followRedirects, null);
	}

	public static String loadHtml(String hostName, String[] headers, Boolean followRedirects) {
		return loadHtml(hostName, headers, followRedirects, null);
	}

	public static String loadHtml(String hostName, String[] headers, Boolean followRedirects, String charset) {
		StringBuffer buffer = null;

		try {
			HttpURLConnection conn = (HttpURLConnection) getConnection(hostName, headers);

			if (followRedirects != null) {
				conn.setInstanceFollowRedirects(followRedirects);
			}

			buffer = getResponseContent(conn, charset);
		} catch (Exception e) {
			System.err.println(String.format("Time: %d\nUrl: %s\nMessage: %s", System.currentTimeMillis(), hostName, e.getMessage()));
			e.printStackTrace();
		}

		if (buffer == null) {
			return null;
		}

		String html = StringEscapeUtils.unescapeHtml(buffer.toString());
		html = VietKeyDecoder.decode(html);

		return html.replace(" ", " ").replaceAll("\\s+", " ");
	}

	public static String loadHtmlByPost(String hostName, String query) {
		return loadHtmlByPost(hostName, query, null, null);
	}

	public static String loadHtmlByPost(String hostName, String query, String[] headers, Boolean followRedirects) {
		StringBuffer buffer = null;
		OutputStream output = null;
		try {
			byte[] bOut = query.getBytes();

			if (ArrayUtils.isEmpty(headers)) {
				headers = FIREFOX_HEADERS.clone();
			}

			headers = (String[]) ArrayUtils.addAll(headers, new String[] {
					"Content-Length", String.valueOf(bOut.length)
			});

			HttpURLConnection conn = (HttpURLConnection) getConnection(hostName, headers);
			if (followRedirects != null) {
				conn.setInstanceFollowRedirects(followRedirects);
			}

			conn.setRequestMethod("POST");
			conn.setDoOutput(true);

			output = conn.getOutputStream();

			output.write(bOut);
			output.flush();

			buffer = getResponseContent(conn, null);
		} catch (Exception e) {
			System.err.println(String.format("Time: %d\nUrl: %s\nMessage: %s", System.currentTimeMillis(), hostName, e.getMessage()));
			e.printStackTrace();
		} finally {
			if (output != null)
				try {
					output.close();
				} catch (IOException logOrIgnore) {
				}
		}

		if (buffer == null) {
			return null;
		}

		String html = StringEscapeUtils.unescapeHtml(buffer.toString()).replace(" ", " ").replaceAll("\\s+", " ");
		html = VietKeyDecoder.decode(html);
		return html;
	}

	public static StringBuffer getResponseContent(HttpURLConnection conn, String charset) {
		StringBuffer buffer = new StringBuffer();
		try {
			InputStream inStream = null;
			try {
				inStream = conn.getInputStream();
			} catch (IOException e) {
				if (conn.getResponseCode() == 500) {
					inStream = conn.getErrorStream();
				}
			}

			if (null == inStream) {
				return null;
			}

			String contentEncoding = conn.getContentEncoding();
			if (StringUtils.isNotBlank(contentEncoding) && contentEncoding.indexOf("gzip") != -1) {
				inStream = new GZIPInputStream(inStream);
			}

			charset = StringUtils.isBlank(charset) ? "UTF-8" : charset;
			BufferedReader in = new BufferedReader(new InputStreamReader(inStream, charset));

			String inputLine;
			while ((inputLine = in.readLine()) != null) {
				buffer.append(inputLine + " ");
			}
			in.close();
		} catch (Exception e) {
			System.err.println(String.format("Time: %d\nUrl: %s\nMessage: %s", System.currentTimeMillis(), conn.getURL().toString(), e.getMessage()));
			e.printStackTrace();
		}

		return buffer;
	}

	public static String parseContent(String responseContent, String tokenStart, String tokenEnd) {
		if (StringUtils.isBlank(responseContent)) {
			return null;
		}

		String tableContent = null;

		int posStart = 0;
		if (StringUtils.isNotBlank(tokenStart)) {
			posStart = responseContent.indexOf(tokenStart);

			if (posStart < 0) {
				return null;
			}
			posStart += tokenStart.length();
		}

		int posEnd = -1;
		if (tokenEnd != null) {
			posEnd = responseContent.indexOf(tokenEnd, posStart);
		}

		if (posEnd > posStart) {
			tableContent = responseContent.substring(posStart, posEnd);
		} else if (posEnd == posStart) {
			return "";
		} else {
			tableContent = responseContent.substring(posStart);
		}

		return tableContent;
	}

	public static String removeText(String html, String tokenStart, String tokenEnd) {
		int startPos = html.indexOf(tokenStart);
		while (startPos > -1) {
			int endPos = html.indexOf(tokenEnd, startPos + tokenStart.length());
			if (endPos == -1) {
				endPos = html.length();
			}
			html = html.substring(0, startPos) + html.substring(endPos);
			startPos = html.indexOf(tokenStart);
		}
		return html;
	}

	public static String removeTextStrictly(String html, String tokenStart, String tokenEnd, int maxRemovedNo) {
		return removeText(html, tokenStart, tokenEnd, maxRemovedNo, false);
	}

	public static String removeText(String html, String tokenStart, String tokenEnd, int maxRemovedNo, boolean includeTokenEnd) {
		int startPos = html.indexOf(tokenStart);
		while ((startPos > -1) && (maxRemovedNo > 0)) {
			int endPos = html.indexOf(tokenEnd, startPos + tokenStart.length());

			if (endPos == -1) {
				break;
			}
			if (includeTokenEnd) {
				endPos += tokenEnd.length();
			}
			html = html.substring(0, startPos) + html.substring(endPos);
			startPos = html.indexOf(tokenStart);
			maxRemovedNo--;
		}
		return html;
	}

	static Pattern	pattern	= Pattern.compile("\\<.*?\\>");

	public static String lowerHtmlTag(String html) {
		StringBuffer result = new StringBuffer();
		Matcher matcher = pattern.matcher(html);
		while (matcher.find()) {
			String tag = matcher.group(0);
			tag = tag.replace("$", "\\$").toLowerCase();
			matcher.appendReplacement(result, tag);
		}
		matcher.appendTail(result);

		return result.toString();
	}

	static Pattern	mediaObjpattern	= Pattern.compile("(<iframe.*?</iframe>)|(<video.*?</video>)");

	public static String replaceMediaObject(String html) {
		StringBuffer result = new StringBuffer();
		Matcher matcher = mediaObjpattern.matcher(html);
		while (matcher.find()) {
			String tag = matcher.group(0).replaceAll("['\"]", "`");
			String src = BaseParser.parseContent(tag, "src=`", "`");
			if (src != null && src.matches("(?i).*((youtu\\.be)|(youtube\\.com)).*")) {
				src = src.replaceAll("(?i).*((youtu\\.be)|(youtube\\.com).*/[\\w_-]+).*", "$1").replaceAll("(?i)youtube\\.com.*/", "youtu.be/").replaceAll(
						"/.+/", "/");
				src = StringUtils.trimToEmpty(src);
				if (StringUtils.isNotEmpty(src)) {
					src = "http://" + src;
				}
				tag = "\n" + src + "\n";
			} else {
				tag = "\n[ **** KHÔNG HỖ TRỢ TRÌNH CHIẾU MULTIMEDIA **** ]\n";
			}

			matcher.appendReplacement(result, tag);
		}
		matcher.appendTail(result);

		return result.toString();
	}

	public static String cleanAttribute(String html) {
		if (html == null) {
			return null;
		}
		return html.replaceAll(" [ ]+", " ").replaceAll("(<[A-Za-z1-4]+)([^>]*>)", "$1>");
	}

	public static String removeHtmlTag(String html) {
		if (html == null) {
			return null;
		}
		return html.replaceAll("\\<.*?\\>", "").replaceAll("\\s+", " ");
	}

	public static String genRetainTags(String[] tagsToRetain) {
		StringBuilder regex = new StringBuilder("</?+");
		if (tagsToRetain.length > 0) {
			regex.append("(?!(?i:").append(tagsToRetain[0]);
			for (int i = 1; i < tagsToRetain.length; i++) {
				regex.append("|").append(tagsToRetain[i]);
			}
			regex.append(")\\b)");
		}
		regex.append("[^<>]++>");
		return regex.toString();
	}

	public static String retainTags(String input, String regex) {
		if (StringUtils.isBlank(input)) {
			return null;
		}

		return input.replaceAll(regex.toString(), " ");
	}

	public static String convert(String string) {
		String out = null;
		try {
			out = new String(string.getBytes("ISO-8859-1"), "utf-8");
		} catch (java.io.UnsupportedEncodingException e) {
			return null;
		}
		return out;

	}

	static Pattern	splitImgPattern	= Pattern.compile("<img (?:[^>]+)>", Pattern.CASE_INSENSITIVE);

	public static String splitImg(String html) {
		Matcher matcher = splitImgPattern.matcher(html);
		return matcher.replaceAll("\n$0\n");
	}

	/**
	 * Điểm đầu được xác định bằng cách dò theo các điểm mốc trong <code>stepTokens</code>
	 */
	public static String traceBetween(String html, String[] stepTokens, String endToken) {
		if (ArrayUtils.isEmpty(stepTokens)) {
			return parseContent(html, null, endToken);
		}
		if (StringUtils.isBlank(html)) {
			return null;
		}

		int posStart = 0;
		for (String token : stepTokens) {
			int pos = indexOf(html, token, posStart);
			if (pos < 0) {
				return null;
			}

			posStart = pos + token.length();
		}

		int posEnd = indexOf(html, endToken, posStart);
		if (posEnd > posStart) {
			return html.substring(posStart, posEnd);
		}

		return null;
	}

	/**
	 * Trả về vị trí xuất hiện của chuỗi <code>searchStr</code> trong chuỗi <code>source</code> <br>
	 * + Nếu chuỗi <code>searchStr</code> bắt đầu bằng ký tự <tt>'$'</tt> thì sẽ tìm từ cuối chuỗi.
	 * */
	public static int indexOf(String source, String searchStr, int fromIndex) {
		if (StringUtils.isBlank(source) || StringUtils.isBlank(searchStr)) {
			return -1;
		}
		if (searchStr.startsWith("$")) {
			return source.lastIndexOf(searchStr.substring(1)) - 1;
		}

		return source.indexOf(searchStr, fromIndex);
	}

	public static String getBaseUrl(String html, String initValue) {
		if (StringUtils.isBlank(html)) {
			return null;
		}
		String norHtml = html.toLowerCase().replaceAll("[`\"]", "'").replaceAll("\\s+?=\\s+?", "=");

		String base = traceBetween(norHtml, new String[] {
				"$<base", "href='"
		}, "'");
		if (StringUtils.isNotBlank(base)) {
			return base;
		}

		base = traceBetween(norHtml, new String[] {
				"$property='og:url'", "content='"
		}, "'");
		if (StringUtils.isBlank(base)) {
			base = initValue;
		}

		return base;
	}
}
